﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace BattleThis.Core.Movement
{
	/// <summary>
	/// ActionPoints a Unit has per round in the game.
	/// </summary>
	[System.Diagnostics.DebuggerDisplay("Current Points {Points} Orginal {Orginal}")]
	public class ActionPoint
	{

		#region Variablen
		/// <summary>
		/// Action Point with zero values.
		/// </summary>
		public static readonly ActionPoint Empty = new ActionPoint();
		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the original.
		/// </summary>
		/// <value>
		/// The original.
		/// </value>
		public int Original { get; protected set; }

		/// <summary>
		/// Gets the current points.
		/// </summary>
		public int Remaining { get; protected set; }
		#endregion

		#region Methoden
		/// <summary>
		/// Prevents a default instance of the <see cref="ActionPoint"/> class from being created.
		/// </summary>
		private ActionPoint()
		{
			this.Remaining = 0;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ActionPoint"/> class.
		/// </summary>
		/// <param name="points">The points.</param>
		public ActionPoint( int original )
		{
			if( original <= 0 )
				throw new ArgumentOutOfRangeException( "points <= 0 is invalid." );

			this.Original = original;
			this.Remaining = original;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ActionPoint"/> class.
		/// </summary>
		/// <param name="original">The original.</param>
		/// <param name="remaining">The remaining.</param>
		public ActionPoint( int original , int remaining )
		{
			if( original <= 0 )
				throw new ArgumentOutOfRangeException( "points <= 0 is invalid." );

			if( remaining < 0 )
				throw new ArgumentOutOfRangeException( "remaining < 0 is invalid." );

			this.Original = original;
			this.Remaining = remaining;
		}

		/// <summary>
		/// Resets this instance.
		/// </summary>
		public void Reset()
		{
			this.Remaining = this.Original;
		}

		/// <summary>
		/// Subtracts this points if entering the specified field and return the remaing ActionPoints.
		/// </summary>
		/// <param name="field">The field to enter.</param>
		/// <returns>Remaining ActionPoints if entering.</returns>
		public ActionPoint Subtract( Field field )
		{
			if( field == null )throw new ArgumentNullException( "field" );

			return this.Subtract( field.LandScape );
		}

		/// <summary>
		/// Subtracts this points if entering the specified field and return the remaing ActionPoints.
		/// </summary>
		/// <param name="Landscape">The Landscape to enter.</param>
		/// <returns>Remaining Action Points if entering.</returns>
		public ActionPoint Subtract( Landscape landscape )
		{
			if( landscape == null )throw new ArgumentNullException( "landscape" );

			var remain =	this.Remaining - landscape.MovementCosts <= 0 ?
									new ActionPoint( this.Original, 0 ) : 
									new ActionPoint( this.Original,  this.Remaining - landscape.MovementCosts );
			return remain;
		}

		/// <summary>
		/// Determines whether this instance is exhausted.
		/// </summary>
		/// <returns>
		///   <c>true</c> if this instance is exhausted; otherwise, <c>false</c>.
		/// </returns>
		public bool IsWasted()
		{
			return this.Remaining <= 0 ;
		}

		/// <summary>
		/// Swaps this instance.
		/// </summary>
		public void Waste()
		{
			this.Remaining = 0;
		}

		/// <summary>
		/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
		/// </summary>
		/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
		/// <returns>
		///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
		/// </returns>
		public override bool Equals( object obj )
		{
			if( obj is ActionPoint )
				return this.Remaining.Equals( ( (ActionPoint)obj ).Remaining );

			return base.Equals( obj );
		}

		/// <summary>
		/// Equalses the specified obj.
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <returns></returns>
		public bool Equals( ActionPoint obj )
		{
			return this.Remaining.Equals( ( obj ).Remaining ) && 
					this.Original.Equals(obj.Original) ;
		}

		/// <summary>
		/// Returns a hash code for this instance.
		/// </summary>
		/// <returns>
		/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
		/// </returns>
		public override int GetHashCode()
		{
			return this.GetHashCode();
		}

		public override string ToString()
		{
			return string.Format("{0}/{1}", this.Remaining, this.Original);
		}

		#endregion

	}
}